---------------------------------------------------------------
-- @Copyright：           zour
-- @Description：         客户端接口函数 调用的 库函数

-- @modify time           2021-10-14
---------------------------------------------------------------
require "modules.business_advert.advert_define"
local advert_account = require "modules.business_advert.advert_account"
local gg = require "modules.business_advert.advert_gg"
local advert_common = require "modules.business_advert.advert_common"
local b_common     = require("modules.business_common.business_common")

local FOO = {}

--=================================== update_config_by_type =====================================
--web原始数据解析
local function parse_web_config(raw_config)
    if #raw_config==0 then 
        return 
    end
    --web最原始的数据是包含了3个table, 第一个table是xlsx的字段中文注释名 [2]是字段名表，[3]是数据表。 三者一一对应
    local t_notes = table.remove(raw_config, 1)
    local t_names = table.remove(raw_config, 1)
    local t_values = raw_config
    local index_nums = #t_names

    local raw_table = {}
    for i=1, #t_values do
        local one_data = {}
        for j=1, index_nums do
            if t_values[i][j] and ( type(t_values[i][j])=="number" or  ( type(t_values[i][j])=="string" and (not string.find(t_values[i][j], "userdata: NULL"))) ) then 
                t_values[i][j] = tonumber(t_values[i][j]) or tostring(t_values[i][j])
                one_data[t_names[j]] = t_values[i][j]
            end
        end
        --这里插入一下序号值[xlsx_id]， 后面需要用到
        one_data.xlsx_id = (i + 2)          --数据上方还有名称，字段名占用了2行要加上
        table.insert(raw_table, one_data)
    end

   return raw_table
end

--按全局定义里的定义数据来整理原始数据
local function change_raw_by_type(raw_config_name, config_type)
    local change_def = CHANGE_CONFIG[config_type]
    local change_types = change_def.type

    ns_config.advert_change_config[raw_config_name] = {}
    --遍历CHANGE_CONFIG中定义的区分类型来进行数据转换
    for _, change_type_def in pairs (change_types) do
        local key_def = change_type_def.key
        local name_def = change_type_def.name

        --若是按渠道分时，还要在渠道里面分平台才行。不太好代码通用化处理，只有拎出来处理了
        local t = {}
        if name_def=="config_channel" then 
            for _, v in ipairs(ns_config.advert_raw_config[raw_config_name]) do
                local v_value = v[key_def] 
                if v_value and v_value~="nil" 
                and v.advert_platform_id and v.advert_platform_id~="nil"
                and v.adsense_id and v.adsense_id~="nil" then 
                    t[ v_value ] = t[ v_value ] or {}
                    t[ v_value ][ v.advert_platform_id ] = t[ v_value ][ v.advert_platform_id ] or {}
                    --策划确认了，渠道+平台可以确定唯一广告位。故这里直接用广告位做key了
                    --table.insert( t[ v_value ][ v.advert_platform_id ],  v)
                    t[v_value][v.advert_platform_id][v.adsense_id] = v
                end
            end
        else
            for _, v in ipairs(ns_config.advert_raw_config[raw_config_name]) do
                local v_value = v[key_def]   --v_value就是 v.adsense_id或者v.channel_id或者v.advert_platform_id等等xlsx表字段
                if v_value and v_value~="nil" then 
                    t[ v_value ] = t[ v_value ] or {}
                    --注意: 其他这里都是直接 table_insert的. [KEY]为无意义的值
                    table.insert(t[v_value], v)
                end
            end
        end 
        ns_config.advert_change_config[raw_config_name][name_def] = t
    end
end

--根据web后台发过来的type值来拉对应的配置数据[web每更新一个XLSX都会下发一次，并附带type值(type值是根据xlsx表数量递增的1,2,3,4...)]
FOO.update_config_by_type = function(type)
    local config_url_name = "advert_config"
    local raw_config_name = WEB_CONFIG_NAME[type]

    --根据type请求web拉取配置数据
    local raw_config = {}
    local code, info = advert_common.get_http_page(ns_config[config_url_name][raw_config_name])
    if code.ret~=ERROR_CODE.OR_SUCCESS.ret then 
        log.day_list(ADVERT, "[ERROR] (process_api：update_config_by_type)".." |[config_url_name]="..config_url_name
            .." |raw_config_name="..raw_config_name.." |[url]= "..ns_config[config_url_name][raw_config_name])
        return code
    else
        raw_config = cjson.decode(info)
    end

    --raw_config
    ns_config.advert_raw_config[raw_config_name] = parse_web_config(raw_config)

    --change_config, 将上面获取到的原始web配置数据转换成易读的配置数据[ 默认用广告位做key来分 ]
    change_raw_by_type(raw_config_name, type)

    --日志记录
    log.day_list(ADVERT, "process_api: update_config_by_type! type="..(type or "nil")
        .." url= "..ns_config[config_url_name][raw_config_name])

    return ERROR_CODE.OR_SUCCESS
end

--请求web更新所有配置
FOO.update_all_config = function()
    --[[
    local ret, body = ns_network.getHttpPage( "https://cdk-test.mini1.cn/api/getAdvertConfig?type=1" )
    log.debug(ret)
    uu.var_dump(body)
    --]]

    --遍历所有
    for _, config_type in pairs(WEB_CONFIG) do
        FOO.update_config_by_type(config_type)
    end

    --更新后的缓存配置表正确性校验
    local check_config_code = FOO.check_config()
    if check_config_code.ret~=ERROR_CODE.OR_SUCCESS.ret then 
        --校验失败就用备份数据还原
        ns_config.advert_raw_config = ns_config.backup_config.advert_raw_config
        ns_config.advert_change_config = ns_config.backup_config.advert_change_config
        log.day_list(ADVERT, "[ERROR]process_api: update_all_config check_config fail!")
        return check_config_code
    end

    return ERROR_CODE.OR_SUCCESS
end

--=================================== get_random_platform =====================================
--权重随机取该渠道下的平台ID
FOO.get_random_platform = function(channel)
    local channel_infos = ns_config.advert_change_config.config.config_channel[channel]
    if not channel_infos then 
        return 
    end

    local platforms = {}
    local total_range = 0
    for platform_id, platform_info in pairs(channel_infos) do
        local one_platform = {}

        one_platform.advert_platform_id = platform_id
        --show_num_percent每个平台只需要计算一个就行 [策划说的]
        one_platform.min = total_range 
        for _, v in pairs(platform_info) do
            --平台开关为1[关]的，不计算
            if tonumber(v.advert_status or 0)~=1 then 
                total_range = total_range + v.show_num_percent
                one_platform.isopen = true
            end

            break
        end
        one_platform.max = total_range 
        
        if one_platform.isopen then 
            table.insert(platforms, one_platform)
        end
    end

    --权重随机命中的平台
    local random_value = math.random(1, total_range)
    local the_platform_id
    for _, v in pairs(platforms) do
        if random_value>v.min and random_value<=v.max then 
            the_platform_id = v.advert_platform_id
            break 
        end
    end

    return the_platform_id
end

--=================================== check_config =====================================
--配置正确性检测
--[[
v1.0.0:
    if (not ns_config.advert_raw_config)                    --web更新下来的原始数据[所有xlsx数据]
    or (not ns_config.advert_raw_config.config)             --xlsx原始数据advert_config[type=1]
    or (not ns_config.advert_raw_config.bouns)              --xlsx原始数据advert_arward[type=2]
    or (not ns_config.advert_change_config)                 --advert_config所有易读分类
    or (not ns_config.advert_change_config.config)          --转换advert_raw_config.config后的所有数据
    or (not ns_config.advert_change_config.config.config_channel)  --广告配置按渠道分类
    or (not ns_config.advert_change_config.config.config_platform) --广告按平台分类 [v0.1.0暂时没用到]
    or (not ns_config.advert_change_config.config.config_absense)  --广告按广告位分类 [v0.1.0暂时没用到]
    or (not ns_config.advert_change_config.bouns)                  --转换advert_raw_config.bouns后的所有数据
    or (not ns_config.advert_change_config.bouns.config_absense) then   --广告奖励按广告位分类
        return ERROR_CODE.OR_CONFIG_ERROR
    end 
]]
FOO.check_config = function ()
    --配置较大，所以就放在每个work进程的缓存里了，没丢到ssdb里[mini_kv文档上说value最好不要超过20K]
    if (not ns_config.advert_raw_config) 
    or (not ns_config.advert_change_config) then 
        log.day_list(ADVERT, "[ERROR] (process_api: check_config) ERROR_1!")
        return ERROR_CODE.OR_CONFIG_ERROR
    end

    --web原始数据正确性检测
    for _, config_type in pairs (WEB_CONFIG) do 
        local raw_config_name = WEB_CONFIG_NAME[config_type]
        if not ns_config.advert_raw_config[raw_config_name] then 
            log.day_list(ADVERT, "[ERROR] (process_api: check_config) ERROR_2!")
            return ERROR_CODE.OR_CONFIG_ERROR
        end
    end

    --转换后的数据正确性检测
    for _, change_def in pairs (CHANGE_CONFIG) do 
        local change_config_name = change_def.name
        local change_config_types = change_def.type

        --
        if not ns_config.advert_change_config[change_config_name] then 
            log.day_list(ADVERT, "[ERROR] (process_api: check_config) ERROR_3!")
            return ERROR_CODE.OR_CONFIG_ERROR
        end
        --types
        for _, change_type_def in pairs(change_config_types) do
            local name_def = change_type_def.name 
            if not ns_config.advert_change_config[change_config_name][name_def] then 
                log.day_list(ADVERT, "[ERROR] (process_api: check_config) ERROR_4!")
                return ERROR_CODE.OR_CONFIG_ERROR
            end
        end
    end

    return ERROR_CODE.OR_SUCCESS
end

--=================================== check_reload_config =====================================
--取广告位对应的奖励配置[奖励配置中会存在多个重复广告位，并且奖励不同，要判断当前是哪一种奖励要通过自己的渠道去确定]
local function get_reward_by_channel(bouns_config, channel)
    --uu.var_dump(bouns_config)
    local bouns = {}
    for index, v in pairs (bouns_config) do
        if tonumber(v.channel_id)==0 or tonumber(v.channel_id)==channel then 
            --策划规定会优先命中 对应渠道的那一行，若无则命中 0不限渠道的这行
            bouns = bouns_config[index]
            --return bouns_config[index]
        else
            for channel_value in string.gmatch(v.channel_id, "(%d+)") do   
                --log.debug("toname value= "..tonumber(channel_value))
                --log.debug("channe= "..channel)
                if tonumber(channel_value)==channel then 
                    return bouns_config[index]
                end
            end
        end
    end

    
    --若取到了对应的奖励表，则 adsense_id 字段是一定有的
    if not bouns.adsense_id then 
        log.day_list(ADVERT, "get_reward_by_channel return {}! channel= "..channel)
    end

    return bouns
end

--不同广告位功能不一样需要赋初始值
local function special_bouns_data(position, one_config)
    one_config.extra = {
        ['type'] = REWARD_SPECIAL_BASE + position,
        ['value'] = 0,
    }
end

--每日数据内容
local function get_change_config_day(position_info, bouns_config)
    local one_config = {} 
    --广告位
    one_config.position_id = position_info.adsense_id
    --平台ID
    one_config.platform_id = position_info.advert_platform_id
    --广告类型 （1:视频, 2:插屏, 3:原生, 4:H5）
    one_config.type = position_info.ad_type

    --是否为开发者广告
    one_config.ad_developer = position_info.ad_developer
    --请求频率
    one_config.cycling_range = position_info.request_frequency_cycling_range
    --请求次数
    one_config.cycling_range_count =  position_info.request_members
    --广告位每人每天总数
    one_config.num_total = position_info.adshow_finish_num_total
    --渠道每人每天总数
    one_config.day_total_finish = position_info.ad_total_finish_count
    --是否发奖
    one_config.give_prizes = position_info.give_prizes
    --时间间隔
    one_config.time_interval = position_info.time_interval
    --[貌似没用了？accounts里注释为]广告触达用户间隔天数(0表示不限制，整数表示间隔天数)
    one_config.player_ad_interval = 0
    --可展示[关闭的广告位会在发送时屏蔽，这里直接给可用了]
    one_config.valid = 1

    --播放完成数据
    one_config.finish = {
        count = 0,      --次数
        ts = 0,         --最后一次播放完成时间
    }
    --展示[曝光]数据
    one_config.show = {
        count = 0,      --次数
        ts = 0,         --最后一次播放时间
    }
    --点击播放数据
    one_config.start = {
        count = 0,
        ts = 0,         --最后一次播放时间
    }
    --是否已达每日该渠道广告位播放上限
    one_config.is_channel_max = 0
    --是否已达每日该广告位每人播放上限
    one_config.is_position_max = 0

    --奖励表数据拼接
    --奖励权重
    if bouns_config[position_info.adsense_id] then 
        local one_reward = get_reward_by_channel(bouns_config[position_info.adsense_id], position_info.channel_id)
        one_config.probability = one_reward.reward_probability
        --触发器广告优先级（配置的数值越小优先级越高， 0或不填按默认按视频>插屏>H5顺序展示）
        one_config.trigger_priority = one_reward.trigger_priority
        --奖励内容数据相关
        one_config.extra = {
            --效果（1减时间、2领取物品、3增加一次分享、4触发器广告、5迷你点）
            ['type'] = one_reward.adsense_effect,   
            --奖励数值
            ['value'] = one_reward.reward_num or 0,
            --获得奖励的尝试次数条件（0或不填无限制）
            ['condition'] = one_reward.reward_try_times,
            --奖励物品ID
            ['reward_id'] = one_reward.reward_id
        }
        one_config.bouns = {
            --这里就是对应奖励表上的一条数据
            ["ID"] = one_reward.xlsx_id,
            ["adsense_id"] = one_reward.adsense_id,
            ["adsense_name"] = one_reward.adsense_name,
            ["adsense_effect"] = one_reward.adsense_effect,
            ["reward_id"] = one_reward.reward_id,
            ["reward_name"] = one_reward.reward_name,
            ["reward_try_times"] = one_reward.reward_try_times,
            ["reward_probability"] = one_reward.reward_probability,
            ["reward_num"] = one_reward.reward_num,
            ["channel_id"] = one_reward.channel_id,
            ["reward_num_add"] = one_reward.reward_num_add,
            
        }
    else
        --还有一些奖励为特殊奖励，不在配置表上，单独拼接奖励表
        special_bouns_data(position_info.adsense_id, one_config)
    end

    return one_config
end

--每周数据内容
local function get_change_config_week()
    local one_config = {}

    --播放完成数据
    one_config.finish = {
        count = 0,      --次数
        ts = 0,         --最后一次播放完成时间
    }
    --点击播放数据
    one_config.start = {
        count = 0,
        ts = 0,         --最后一次播放时间
    }
    --曝光数据
    one_config.show = {
        count = 0,      --次数
        ts = 0,         --最后一次播放时间
    }

    return one_config
end

--转换成易读配置
local function get_change_config(raw_config, bouns_config)
    --每日
    local change_config_day = get_change_config_day(raw_config, bouns_config)
    --每周   
    local change_config_week = get_change_config_week() 

    return change_config_day, change_config_week
end

--初始化玩家配置
FOO.init_user_config = function(channel, platform_id, position_id)
    local user_config_info = {}
    --时间相关
    user_config_info.time = {}
    user_config_info.time["web_update_config"] = ns_config.update_time
    user_config_info.time["today"] = advert_common.get_day_zero(uu.now())
    user_config_info.time["week"] = advert_common.get_week_zero(uu.now())
    --配置数据相关
    local user_raw_config = ns_config.advert_change_config.config.config_channel[channel][platform_id][position_id]

    user_config_info.config = {}
    user_config_info.config.raw_config = user_raw_config  
    user_config_info.config.change_config = {}
    user_config_info.config.change_config.today, 
    user_config_info.config.change_config.week = get_change_config(user_raw_config, ns_config.advert_change_config.bouns.config_absense)

    return user_config_info
end

--每天复位玩家配置数据
local function reset_user_config_day(user_config_info)
    --时间相关
    user_config_info.time["today"] = advert_common.get_day_zero(uu.now())

    --配置数据相关
    local today_data = user_config_info.config.change_config.today
    --曝光次数
    today_data.show.count = 0
    --播放次数
    today_data.start.count = 0
    --播放完成次数
    today_data.finish.count = 0
    --是否已达每日该渠道广告位播放上限
    today_data.is_channel_max = 0
    --是否已达每日该广告位每人播放上限
    today_data.is_position_max = 0
    --extra的value数据也要复位
    today_data.extra.value = 0
    if today_data.bouns then 
        today_data.extra.value = today_data.bouns.reward_num or 0
    end
end

--每周复位玩家配置数据
local function reset_user_config_week(user_config_info)
    --时间相关
    user_config_info.time["week"] = advert_common.get_week_zero(uu.now())
    
    --配置数据相关
    local week_data = user_config_info.config.change_config.week
    --曝光次数
    week_data.show.count = 0
    --播放次数
    week_data.start.count = 0
    --播放完成次数
    week_data.finish.count = 0
end

--
local function add_patch_config(old_today_data, old_week_data)
    --日
    if not old_today_data.finish then 
        old_today_data.finish = {}
        old_today_data.finish.count = 0
        old_today_data.finish.ts = 0
    end
    if not old_today_data.show then 
        old_today_data.show = {}
        old_today_data.show.count = 0
        old_today_data.show.ts = 0
    end
    if not old_today_data.start then 
        old_today_data.start = {}
        old_today_data.start.count = 0
        old_today_data.start.ts = 0
    end

    --周
    if not old_week_data.finish then 
        old_week_data.finish = {}
        old_week_data.finish.count = 0
        old_week_data.finish.ts = 0
    end
    if not old_week_data.show then 
        old_week_data.show = {}
        old_week_data.show.count = 0
        old_week_data.show.ts = 0
    end
    if not old_week_data.start then 
        old_week_data.start = {}
        old_week_data.start.count = 0
        old_week_data.start.ts = 0
    end
end

--纯配置更新
local function update_user_config(user_config_info, channel, platform_id, position_id)
    user_config_info.time["web_update_config"] = ns_config.update_time

    local raw_config = ns_config.advert_change_config.config.config_channel[channel][platform_id][position_id]
    user_config_info.config.raw_config = raw_config  

    --配置更新只更新配置相关数据， 广告处理相关数据不能被修改
    local old_today_data = user_config_info.config.change_config.today
    local old_week_data = user_config_info.config.change_config.week
    user_config_info.config.change_config.today,
    user_config_info.config.change_config.week = get_change_config(raw_config, ns_config.advert_change_config.bouns.config_absense)

    --补丁数据[若后续配置修改结构字段，通过这里更新就不会影响玩家数据]
    add_patch_config(old_today_data, old_week_data)

    --数据还是要用之前的
    local new_today_data = user_config_info.config.change_config.today 
    local new_week_data = user_config_info.config.change_config.week
    --日
    new_today_data.finish.count = old_today_data.finish.count or 0
    new_today_data.finish.ts = old_today_data.finish.ts or 0
    new_today_data.show.count = old_today_data.show.count or 0
    new_today_data.show.ts = old_today_data.show.ts or 0
    new_today_data.start.count = old_today_data.start.count or 0
    new_today_data.start.ts = old_today_data.start.ts or 0
    --周
    new_week_data.finish.count = old_week_data.finish.count or 0
    new_week_data.finish.ts = old_week_data.finish.ts or 0
    new_week_data.show.count = old_week_data.show.count or 0
    new_week_data.show.ts = old_week_data.show.ts or 0
    new_week_data.start.count = old_week_data.start.count or 0
    new_week_data.start.ts = old_week_data.start.ts or 0
end

--检测从SSDB读取的内容是否要重新加载配置里的数据  
FOO.check_reload_config = function(user_config_info, channel, platform_id, position_id, uin)
    local reload_flag = false

    --该玩家还未初始化[第一次登广告服，SSDB里还没其数据时]  [所有值都校验一遍nil]
    if (not user_config_info) 
    or (not user_config_info.time) 
    or (not user_config_info.time.today)
    or (not user_config_info.time.week)
    or (not user_config_info.time.web_update_config)
    or (not user_config_info.config.raw_config)   
    or (not user_config_info.config.change_config.today)
    or (not user_config_info.config.change_config.week) then 
        --log.day_list(ADVERT, "(process_api: check_reload_config [INIT USER_CONFIG]) user_config_info=={} !"
            --.." uin= "..uin.." channel="..channel.." platform_id"..platform_id.." position_id="..position_id)

        user_config_info = FOO.init_user_config(channel, platform_id, position_id)
        reload_flag = true
    end

    --广告配置相关的数据 是否最新
    if user_config_info.time.web_update_config~=ns_config.update_time then 
        --log.day_list(ADVERT, "process_api: check_reload_config [RESET WEB_UPDATE] uu.now= "..uu.now().." web_update_time="
            --..(ns_config.update_time or "nil").." ssdb_user_ts=".. (user_config_info.time.web_update_config or "nil") )

        update_user_config(user_config_info, channel, platform_id, position_id)
        reload_flag = true
    end

    --玩家的广告相关数据每天是否复位了
    local server_ts_day = advert_common.get_day_zero(uu.now())
    if user_config_info.time.today~=server_ts_day then 
        --log.day_list(ADVERT, "process_api: check_reload_config [RESET DAY] uu.now= "..uu.now().." server_ts="
            --..server_ts_day.." ssdb_user_ts=".. (user_config_info.time.today or "nil"))

        reset_user_config_day(user_config_info)
        reload_flag = true
    end

    --玩家的广告数据每周是否复位了
    local server_ts_week = advert_common.get_week_zero(uu.now())
    if user_config_info.time.week~=server_ts_week then 
        --log.day_list(ADVERT, "process_api: check_reload_config [RESET WEEK] uu.now= "..uu.now().." server_ts="
            --..server_ts_week.." ssdb_user_ts=".. (user_config_info.time.week or "nil") )

        reset_user_config_week(user_config_info)
        reload_flag = true
    end

    --若有更新，回写SSDB
    if reload_flag==true then 
        --写入ssdb
        local ssdb_key_ad_info = FOO.calc_ssdb_hash_ad_info(channel, platform_id, position_id) 
        local ret = gg.private_hash_set_table_ssdb(uin%10, uin, ssdb_key_ad_info, user_config_info)
        if ret~="OK" then 
            --log.day_list(ADVERT, "[WARNING] (process_api: check_reload_config) private_hash_set_table_ssdb [ret NONE]")
        end
    end

    return user_config_info
end

--=================================== send_rewards =====================================
--生成所有奖励表
local function creat_reward_table(t)
    local reward_table = {}

    for v in string.gmatch(tostring(t.extra.type), "(%d+)") do
        table.insert(reward_table, {type=tonumber(v)})
    end
    --奖励物品ID表
    if t.extra.reward_id then 
        local index = 0
        local reward_id = string.gsub(t.extra.reward_id, "|", " ")
        for v in string.gmatch(reward_id, "(%S+)") do
            index = index + 1
            reward_table[index].reward_id = (tonumber(v) or v )
        end
    end
    --奖励权重表
    if t.probability then 
        local index = 0
        local probability = string.gsub(t.probability, "|", " ")
        for v in string.gmatch(probability, "(%S+)") do
            index = index + 1
            reward_table[index].probability = (tonumber(v) or v )
        end
    end
    --奖励数值表
    if t.extra.value then 
        local index = 0
        local value = string.gsub(t.extra.value, "|", " ")
        for v in string.gmatch(value, "(%S+)") do
            index = index + 1
            reward_table[index].value = (tonumber(v) or v )
        end
    end
   
    return reward_table
end

--将表数据整理易读
local function order_data(t)
    local reward_table_data = {}
    for _, one_reward in ipairs(t) do
        reward_table_data[one_reward.type] = reward_table_data[one_reward.type] or {}
        --物品id
        if one_reward.reward_id then 
            local index = 0
            for v in string.gmatch(one_reward.reward_id, "(%d+)") do
                index = index + 1
                reward_table_data[one_reward.type][index] = reward_table_data[one_reward.type][index] or {}
                reward_table_data[one_reward.type][index].reward_id = v
            end
        end
        --权重
        if one_reward.probability then 
            local index = 0
            local pro = 0
            for v in string.gmatch(one_reward.probability, "(%d+)") do
                index = index + 1
                reward_table_data[one_reward.type][index] = reward_table_data[one_reward.type][index] or {}
                reward_table_data[one_reward.type][index].probability = {min=pro, max=pro+v}
                pro = pro + v
            end
            reward_table_data[one_reward.type].total_weight = pro
        end 
        --奖励数量
        if one_reward.value then 
        local index = 0
            for v in string.gmatch(one_reward.value, "(%d+)") do
                index = index + 1
                reward_table_data[one_reward.type][index] = reward_table_data[one_reward.type][index] or {}
                reward_table_data[one_reward.type][index].value = v
            end
        end 
    end    

    return reward_table_data
end

--取所有奖励表
local function order_rewards_data(t)
    --第一步： 生成所有奖励表
    local reward_table = creat_reward_table(t)
    --第二步： 将表数据整理易读
    local reward_table_data = order_data(reward_table)

    return reward_table_data
end

--根据奖励表取发送到账号服的奖励内容
local function get_account_reward(t)
    local reward = {}
    local random_num = math.random(1, t.total_weight)
    for _, v in pairs(t) do
        if random_num>v.probability.min and random_num<=v.probability.max then 
            reward.value = v.value
            reward.reward_id = v.reward_id
            --reward.random_num = random_num
            break
        end
    end

    if (not reward.value) or (not reward.reward_id) then 
        log.day_list(ADVERT, "[ERROR] get_account_reward reward={}!") 
    end

    return reward
end

--因为奖励效果不同，2和5是直接下发道具，其他各不一样，故再分类
local function classify_reward_data(t)
    local reward_data = {}
    --账号服发奖励表
    reward_data.call_account = {}
    
    --
    for k, v in pairs(t) do
        --2和5是调用账号服
        if k==REWARD_TYPE.GET_ITEMS or k==REWARD_TYPE.GET_MINIDIAN then 
            table.insert(reward_data.call_account, get_account_reward(v))
        elseif k > REWARD_SPECIAL_BASE then 
            --特殊奖励发奖fix
        end
    end

    return reward_data
end

--看广告发奖励
--效果（1减时间、2领取物品、3增加一次分享、4触发器广告 5发迷你点）
FOO.send_rewards = function(t)
    --取所有奖励表
    local reward_table_data = order_rewards_data(t)
    --分类奖励表
    local reward_data = classify_reward_data(reward_table_data)
    
    --账号服发奖励
    local items = {}
	for _, v in pairs (reward_data.call_account) do
		table.insert(items, {id = v.reward_id, num = v.value})
	end
    if #items>0 then 
        local ret = advert_account.items_add(items)
        if not ret then 
            return ERROR_CODE.OR_FAIL
        end
    end 

    --其他奖励

    return ERROR_CODE.OR_SUCCESS
end

--=================================== get_user_data =====================================
--取玩家SSDB中对应 渠道和广告位的 广告数据
FOO.get_user_data = function(uin, channel, platform_id, position_id)
    --获取该广告位的具体信息
    local ssdb_key_ad_info = FOO.calc_ssdb_hash_ad_info(channel, platform_id, position_id)   
    local user_config_info = gg.private_hash_get_table_ssdb(uin%10, uin, ssdb_key_ad_info)
    if (not user_config_info.time) 
    or (not user_config_info.config) 
    or (not user_config_info.config.change_config) 
    or (not user_config_info.config.change_config.today) 
    or (not user_config_info.config.change_config.week)then 
        --log.day_list(ADVERT, "[ERROR] (get_user_data user_config_info=={} !".." uin="..uin
            --.." ssdb key= "..ssdb_key_ad_info)
        return ERROR_CODE.OR_GET_ADINFO_FAIL
    end

    --获取当天播放数据
    local today_ad_position_info = user_config_info.config.change_config.today
    if (not today_ad_position_info.show) 
    or (not today_ad_position_info.finish) 
    or (not today_ad_position_info.start) then 
        log.day_list(ADVERT, "[ERROR] (get_user_data today.show=={} !".." uin="..uin
            .." channel="..channel.." platform="..platform_id.." position_id= "..position_id)
        return ERROR_CODE.OR_GET_ADINFO_FAIL
    end

    --获取周播放数据
    local week_ad_position_info = user_config_info.config.change_config.week
    if (not week_ad_position_info.show) 
    or (not week_ad_position_info.finish) then
        log.day_list(ADVERT, "[ERROR] (get_user_data week.show=={} !".." uin="..uin
            .." channel="..channel.." platform="..platform_id.." position_id= "..position_id)
        return ERROR_CODE.OR_GET_ADINFO_FAIL
    end

    return ERROR_CODE.OR_SUCCESS, user_config_info
end

--=================================== modify_user_data =====================================
--需要根据配置做特殊处理的广告位信息
local function special_ad_info(position_info)
    --5号位果实缩短需要按次数递增
    if position_info.position_id==5 then
        position_info.extra.value = position_info.bouns.reward_num + position_info.bouns.reward_num_add*position_info.finish.count
    end
end

--finish函数还要加几十个数据打点，为避免代码太长，修改数据这部分拎出来
FOO.user_finish_advert = function(user_config_info, infos)
    local channel = infos.channel_id
    --修改每日数据
    local today_ad_position_info = user_config_info.config.change_config.today
    today_ad_position_info.finish.count = (today_ad_position_info.finish.count or 0) + 1
    today_ad_position_info.finish.ts = uu.now()
    --修改每周数据
    local week_ad_position_info = user_config_info.config.change_config.week
    week_ad_position_info.finish.count = (week_ad_position_info.finish.count or 0) + 1
    week_ad_position_info.finish.ts = uu.now()
    --播放状态复位
    user_config_info.time.isstart = false
      
    special_ad_info(today_ad_position_info)
    
    --是否已达每日该广告位播放上限
    if today_ad_position_info.finish.count>=user_config_info.config.raw_config.adshow_finish_num_total then 
        today_ad_position_info.is_position_max = 1
    end
 
end

--=================================== calc_ssdb_key_ad_info =====================================
--根据uin, channel, platform_id, position_id 这四个值得到ssdb中广告信息唯一key.
--这里暂时直接拼接，用该接口封装便于后续扩展或者修改维护
FOO.calc_ssdb_key_ad_info = function(uin, channel, platform_id, position_id)
    local ssdb_key_ret = tostring(uin).."_"..tostring(channel).."_"
        ..tostring(platform_id).."_"..tostring(position_id)

    return ssdb_key_ret
end

--经确认，hash是可以用string的，这样以uin作key查数据才方便
FOO.calc_ssdb_hash_ad_info = function(channel, platform_id, position_id)
    local ssdb_key_ret = tostring(channel).."_"
        ..tostring(platform_id).."_"..tostring(position_id)

    return ssdb_key_ret
end

--=================================== check_show_freq =====================================
--检测播放频率是否合法
FOO.check_show_freq = function(ad_last_time, ad_type, now_time)
    local def_time = AD_SHOW_TIME[ad_type] or 0

    if (ad_last_time + def_time) > now_time then 
       return ERROR_CODE.OR_HIGH_FREQ 
    end

    return ERROR_CODE.OR_SUCCESS
end

--检测版本号是否关闭
FOO.check_ver_close = function(version_string, client_ver)
    if not version_string or type(version_string)~='string' then 
		return false
	end

	local ver_t = {}
	for v in string.gmatch(version_string, "([^%,]+)") do
        print(v)
		table.insert(ver_t, v )
	end
    
	local n1,n2,n3 = string.match(client_ver, "(%d).(%d).(%d)")
	local all_version = n1.."."..n2..".*"
	for _, close_version in pairs(ver_t) do
		if (close_version==client_ver) or  (close_version==all_version) then 
			return true
		end
	end

	return false
end

return FOO